8   ' *** (FFT09-01.BAS) Q = 2^N POINT FFT ***

10 SCREEN 9, 1, 1: COLOR 15, 1

12 CLS : PRINT : PRINT "INPUT NUMBER OF DATA POINTS AS 2^N"

14 INPUT "N = "; N

16 Q = 2 ^ N: Q1 = Q - 1: N1 = N - 1: X0 = 10

18 Q2 = Q / 2: Q3 = Q2 - 1: Q4 = Q / 4: Q5 = Q4 - 1: Q8 = Q / 8

20 DIM C(Q), S(Q), KC(Q), KS(Q)

22 PI = 3.141592653589793#: P2 = 2 * PI: K1 = P2 / Q: XSF = 600 / Q

24 '  **** TWIDDLE FACTOR TABLE GENERATION ****

28 FOR I = 0 TO Q: KC(I) = COS(K1 * I): KS(I) = SIN(K1 * I)

30 IF ABS(KC(I)) < .0000005 THEN KC(I) = 0 ' CLEANUP TABLE

32 IF ABS(KS(I)) < .0000005 THEN KS(I) = 0

34 NEXT I

36 FOR I = 1 TO Q1: INDX = 0

38 FOR J = 0 TO N1

40 IF I AND 2 ^ J THEN INDX = INDX + 2 ^ (N1 - J)

42 NEXT J

44 IF INDX > I THEN SWAP KC(I), KC(INDX): SWAP KS(I), KS(INDX)

46 NEXT I

48 CLS

50 PRINT SPC(30); "MAIN MENU": PRINT : PRINT

60 PRINT SPC(5); "1 = ANALYZE Q/2 COMPONENT TRIANGLE": PRINT

62 PRINT SPC(5); "2 = INVERSE TRANSFORM": PRINT

64 PRINT SPC(5); "3 = DISPLAY MODE": PRINT

66 PRINT SPC(5); "4 = EXIT": PRINT

70 PRINT SPC(10); "MAKE SELECTION :";

80 A$ = INKEY$: IF A$ = "" THEN 80

90 A = VAL(A$): ON A GOSUB 600, 700, 1180, 990

95 GOTO 40

100   ' *** FFT ***

102 CLS : HDR$ = "FREQ   F(COS)       F(SIN)       "

104 HDR$ = HDR$ + "FREQ   F(COS)       F(SIN)"

106 PRINT HDR$: PRINT

108 T9 = TIMER

110   ' *** FFT ROUTINE ***

112 FOR M = 0 TO N1: QT = 2 ^ (N - M): QT1 = QT - 1

114 QT2 = QT / 2: QT3 = QT2 - 1: KT = 0

116   ' *** UNIVERSAL BUTTERFLY ***

118 FOR J = 0 TO Q1 STEP QT: KT2 = KT + 1

120 FOR I = 0 TO QT3: J1 = I + J: K = J1 + QT2

122 CTEMP = (C(J1) + C(K) * KC(KT) - K6 * S(K) * KS(KT)) / SK1

124 STEMP = (S(J1) + K6 * C(K) * KS(KT) + S(K) * KC(KT)) / SK1

126 CTEMP2 = (C(J1) + C(K) * KC(KT2) - K6 * S(K) * KS(KT2)) / SK1

128 S(K) = (S(J1) + K6 * C(K) * KS(KT2) + S(K) * KC(KT2)) / SK1

130 C(K) = CTEMP2: C(J1) = CTEMP: S(J1) = STEMP

132 NEXT I

134 KT = KT + 2: NEXT J

136 NEXT M

140 ' ***  BIT REVERSAL FOR FINAL DATA ***

142 FOR I = 1 TO Q1: INDX = 0

144 FOR J = 0 TO N1

146 IF I AND 2 ^ J THEN INDX = INDX + 2 ^ (N1 - J)

148 NEXT J

150 IF INDX > I THEN SWAP C(I), C(INDX): SWAP S(I), S(INDX)

152 NEXT I

160 T9 = TIMER - T9

162 GOSUB 1200

170 RETURN

200 ' ********  DISPLAY ROUTINE  **********

210 FOR Z = 0 TO Q2 - 1

215 GOSUB 300

220 NEXT Z

222 PRINT : PRINT "TIME ="; T9

225 PRINT : PRINT : INPUT "C/R TO CONTINUE:"; A$

230 RETURN

300 PRINT USING "####"; Z; : PRINT "   ";

310 PRINT USING "+##.######"; C(Z); : PRINT "    ";

312 PRINT USING "+##.######"; S(Z); : PRINT "      ";

320 PRINT USING "####"; Z + Q2; : PRINT "   ";

322 PRINT USING "+##.######"; C(Z + Q2); : PRINT "    ";

324 PRINT USING "+##.######"; S(Z + Q2)

330 RETURN

400   ' GENERATE Q/2 COMPONENT TRIANGLE WAVE

T8 = TIMER + 1: DISFLG = 1

408 IF Q / 2 > 1024 THEN QT = 1024 ELSE QT = Q / 2

410 FOR I = 0 TO Q: C(I) = 0: S(I) = 0

420 FOR J = 1 TO QT STEP 2: C(I) = C(I) + COS(K1 * J * I) / (J * J): NEXT

422 IF TIMER > T8 THEN GOSUB 500

430 NEXT I

440 RETURN

500   ' *** BLINK WAIT MESSAGE ***

510 DISFLG = 1 - DISFLG

520 IF DISFLG = 1 THEN CLS : GOTO 550

530 LOCATE 10, 22

540 PRINT "PREPARING DATA - PLEASE WAIT"

550 T8 = TIMER + 1: RETURN

600   ' * Q/2 COMPONENT TRIANGLE *

602 CLS : PRINT : PRINT

604 'PRINT "PREPARING DATA INPUT - PLEASE WAIT!"

610 GOSUB 400

612 SK1 = 2: K6 = 1

614 PRINT : INPUT "DATA READY - ENTER TO CONTINUE"; A$

620 GOSUB 100

630 RETURN



700   ' *** INVERSE TRANSFORM ***

710 SK1 = 1: K6 = -1

712 CLS : HDR$ = "TIME    AMPLITUDE   NOT USED     "

714 HDR$ = HDR$ + "TIME   AMPLITUDE     NOT USED"

720 GOSUB 106

730 RETURN



990 END: STOP



1179 ' ***   MODIFY SYSTEM PARAMETERS   ***

1180 CLS

1182 INPUT "PRESENT DATA GRAPHICALLY? (Y/N):"; A$

1184 IF A$ = "Y" OR A$ = "y" THEN IOFLG = 1 ELSE IOFLG = -1

1186 RETURN



'   *****  OUTPUT DATA  *****

1200 'T9 = TIMER - T9

1202 IF IOFLG = 1 THEN 1250

1206 ZSTP = 15

1208 'CLS : PRINT SPC(10); "FREQUENCY DOMAIN DATA": PRINT

1210 FOR Z = 0 TO Q2 - 1

1215 GOSUB 1300

1216 IF Z > ZSTP THEN 1350 ' PRINT 1 SCREEN AT A TIME

1220 NEXT Z

1222 LOCATE 1, 1: PRINT : PRINT "TIME ="; T9

1225 INPUT "ENTER TO CONTINUE:"; A$

1229 RETURN



1250   ' *** PLOT OUTPUT ***

1252 CLS : YPX = 0: IF K6 = 1 THEN 1280

1254 Y0 = 175: X0 = 10

1256 FOR I = 0 TO Q - 1

1258 IF C(I) > YPX THEN YPX = C(I)

1260 NEXT I

11262 YSF = 100 / YPX

1263 LINE (X0 + 10, Y0 - 100)-(X0, Y0 - 100)

1264 LOCATE 6, 1: PRINT USING "###.##"; YPX

1265 LINE (X0 - 1, 50)-(X0 - 1, 300)

1266 LINE (X0 + 600, Y0)-(X0, Y0)

1268 LINE (X0, Y0)-(X0, Y0)

1270 FOR I = 0 TO Q - 1

1272 YP = C(I)

1274 IF K6 = 1 THEN YP = SQR(C(I) ^ 2 + S(I) ^ 2)

1276 LINE -(X0 + XSF * I, Y0 - YSF * YP)

1278 NEXT I

1279 GOTO 1222

1280 ' ***   FIND Y SCALE FACTOR FOR FREQ DOMAIN PLOT   ***

1281 Y0 = 300 ' SET Y AXIS ORIGIN

1282 FOR I = 0 TO Q - 1 ' FIND LARGEST VALUE IN ARRAY

1284 YP = SQR(C(I) ^ 2 + S(I) ^ 2): IF YP > YPX THEN YPX = YP

1286 NEXT I

1287 YSF = 200 / YPX ' SET SCALE FACTOR

1288 LINE (X0 + 10, Y0 - 200)-(X0, Y0 - 200)

1289 LOCATE 8, 1: PRINT USING "###.##"; YPX: GOTO 1265



1300 PRINT USING "####_  "; Z;

1310 PRINT USING "+##.#####"; C(Z); : PRINT "    ";

1312 PRINT USING "+##.#####"; S(Z); : PRINT "      ";

1320 PRINT USING "####_  "; Z + Q2;

1322 PRINT USING "+##.#####"; C(Z + Q2); : PRINT "    ";

1324 PRINT USING "+##.#####"; S(Z + Q2)

1330 RETURN



1350   ' *** STOP WHEN SCREEN FULL ***

1352 ZSTP = ZSTP + 16

1354 PRINT : PRINT "ENTER TO CONTINUE - ESC TO EXIT:"

1356 A$ = INKEY$: IF A$ = "" THEN 1356

1366 IF ASC(A$) = 27 THEN Z = Q3 - 15: ZSTP = Z + 15

1368 CLS : PRINT HDR$: PRINT : PRINT

1370 GOTO 1220



